<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jupyter Notebook 转 Markdown 工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        danger: '#EF4444',
                        warning: '#F59E0B',
                        info: '#64748B'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif']
                    }
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .transition-all-300 {
                transition: all 300ms ease-in-out;
            }
            .shadow-custom {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
            }
            .bg-gradient-blue {
                background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
            }
        }
    </style>
</head>

<body class="bg-gray-50 min-h-screen">
    <div class="max-w-6xl mx-auto px-4 py-8">
        <!-- 标题区域 -->
        <header class="mb-8 text-center">
            <h1 class="text-[clamp(1.8rem,5vw,3rem)] font-bold text-gray-800 mb-2">
                <i class="fa fa-exchange text-primary mr-2"></i>Jupyter Notebook 转 Markdown 工具
            </h1>
            <p class="text-gray-600 text-lg">简单高效的在线转换服务，支持批量处理</p>
        </header>

        <!-- 主内容区域 -->
        <main class="bg-white rounded-xl shadow-custom p-6 mb-8">
            <!-- 文件上传区域 -->
            <section id="upload-section" class="mb-8">
                <div class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary transition-all-300 cursor-pointer"
                    id="drop-area">
                    <i class="fa fa-cloud-upload text-5xl text-gray-400 mb-4"></i>
                    <h3 class="text-xl font-semibold text-gray-700 mb-2">拖放文件到此处上传</h3>
                    <p class="text-gray-500 mb-4">或点击下方按钮选择文件</p>
                    <input type="file" id="file-input" accept=".ipynb" multiple class="hidden">
                    <button id="select-files-btn"
                        class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-6 rounded-lg transition-all-300 flex items-center justify-center mx-auto">
                        <i class="fa fa-file-text-o mr-2"></i>选择 .ipynb 文件
                    </button>
                    <p class="text-sm text-gray-500 mt-4">支持单个或多个 .ipynb 文件，最大 50MB</p>
                </div>

                <!-- 已选文件列表 -->
                <div id="file-list" class="mt-4 hidden">
                    <h4 class="font-medium text-gray-700 mb-2">已选择的文件：</h4>
                    <ul id="selected-files" class="list-disc list-inside text-gray-600 max-h-40 overflow-y-auto"></ul>
                    <button id="clear-files-btn"
                        class="text-primary hover:text-primary/80 mt-2 text-sm flex items-center">
                        <i class="fa fa-times mr-1"></i>清空列表
                    </button>
                </div>
            </section>

            <!-- 转换控制区域 -->
            <section id="control-section" class="mb-8 flex flex-col sm:flex-row justify-between items-center gap-4">
                <div id="task-info" class="text-gray-600 text-sm hidden">
                    <span id="task-id-display">任务ID：</span>
                </div>
                <div class="flex gap-3">
                    <button id="convert-btn"
                        class="bg-gradient-blue text-white font-medium py-2.5 px-6 rounded-lg transition-all-300 flex items-center disabled:opacity-50 disabled:cursor-not-allowed"
                        disabled>
                        <i class="fa fa-play-circle mr-2"></i>开始转换
                    </button>
                    <button id="stop-btn"
                        class="bg-gray-200 text-gray-700 font-medium py-2.5 px-6 rounded-lg transition-all-300 flex items-center hidden">
                        <i class="fa fa-stop-circle mr-2"></i>停止转换
                    </button>
                    <button id="download-all-btn"
                        class="bg-secondary text-white font-medium py-2.5 px-6 rounded-lg transition-all-300 flex items-center hidden">
                        <i class="fa fa-download mr-2"></i>批量下载
                    </button>
                </div>
            </section>

            <!-- 进度条区域 -->
            <section id="progress-section" class="mb-8 hidden">
                <div class="w-full bg-gray-200 rounded-full h-2.5">
                    <div id="progress-bar" class="bg-secondary h-2.5 rounded-full transition-all duration-300"
                        style="width: 0%"></div>
                </div>
                <div class="flex justify-between mt-1">
                    <span id="progress-text" class="text-sm text-gray-600">0%</span>
                    <span id="status-text" class="text-sm text-gray-600">准备就绪</span>
                </div>
            </section>

            <!-- 结果区域 -->
            <section id="results-section" class="mb-8 hidden">
                <h3 class="text-xl font-semibold text-gray-700 mb-4">转换结果</h3>
                <div id="results-list" class="space-y-3"></div>
            </section>

            <!-- 日志区域 -->
            <section id="logs-section" class="mb-4">
                <div class="flex justify-between items-center mb-2">
                    <h3 class="text-lg font-semibold text-gray-700">转换日志</h3>
                    <button id="clear-logs-btn" class="text-primary hover:text-primary/80 text-sm flex items-center">
                        <i class="fa fa-refresh mr-1"></i>清空日志
                    </button>
                </div>
                <div id="logs-container"
                    class="border border-gray-200 rounded-lg p-4 h-64 overflow-y-auto bg-gray-50 text-sm text-gray-700 font-mono">
                    <p class="text-gray-500 italic">等待转换开始...</p>
                </div>
            </section>
        </main>

        <!-- 页脚 -->
        <footer class="text-center text-gray-500 text-sm">
            <p>© 2023 Jupyter Notebook 转 Markdown 工具 | 基于 Flask 和 Docker</p>
        </footer>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const fileInput = document.getElementById('file-input');
            const dropArea = document.getElementById('drop-area');
            const selectFilesBtn = document.getElementById('select-files-btn');
            const clearFilesBtn = document.getElementById('clear-files-btn');
            const fileList = document.getElementById('file-list');
            const selectedFiles = document.getElementById('selected-files');
            const convertBtn = document.getElementById('convert-btn');
            const stopBtn = document.getElementById('stop-btn');
            const progressSection = document.getElementById('progress-section');
            const progressBar = document.getElementById('progress-bar');
            const progressText = document.getElementById('progress-text');
            const statusText = document.getElementById('status-text');
            const logsContainer = document.getElementById('logs-container');
            const clearLogsBtn = document.getElementById('clear-logs-btn');
            const resultsSection = document.getElementById('results-section');
            const resultsList = document.getElementById('results-list');
            const taskInfo = document.getElementById('task-info');
            const taskIdDisplay = document.getElementById('task-id-display');
            const uploadSection = document.getElementById('upload-section');

            let currentTaskId = null;
            let statusCheckInterval = null;

            // 文件选择事件
            selectFilesBtn.addEventListener('click', () => {
                fileInput.click();
            });

            fileInput.addEventListener('change', updateFileList);

            // 拖放功能
            ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
                dropArea.addEventListener(eventName, preventDefaults, false);
            });

            function preventDefaults(e) {
                e.preventDefault();
                e.stopPropagation();
            }

            ['dragenter', 'dragover'].forEach(eventName => {
                dropArea.addEventListener(eventName, highlight, false);
            });

            ['dragleave', 'drop'].forEach(eventName => {
                dropArea.addEventListener(eventName, unhighlight, false);
            });

            function highlight() {
                dropArea.classList.add('border-primary', 'bg-blue-50');
            }

            function unhighlight() {
                dropArea.classList.remove('border-primary', 'bg-blue-50');
            }

            dropArea.addEventListener('drop', handleDrop, false);

            function handleDrop(e) {
                const dt = e.dataTransfer;
                const files = dt.files;
                fileInput.files = files;
                updateFileList();
            }

            function updateFileList() {
                if (fileInput.files.length > 0) {
                    fileList.classList.remove('hidden');
                    selectedFiles.innerHTML = '';

                    Array.from(fileInput.files).forEach(file => {
                        if (file.name.endsWith('.ipynb')) {
                            const li = document.createElement('li');
                            li.textContent = file.name;
                            selectedFiles.appendChild(li);
                        }
                    });

                    convertBtn.disabled = false;
                } else {
                    fileList.classList.add('hidden');
                    convertBtn.disabled = true;
                }
            }

            clearFilesBtn.addEventListener('click', () => {
                fileInput.value = '';
                updateFileList();
            });

            // 转换按钮事件
            convertBtn.addEventListener('click', function () {
                if (convertBtn.textContent.trim() === '开始转换') {
                    startConversion();
                } else {
                    // 重置功能
                    resetApplication();
                }
            });
            stopBtn.addEventListener('click', stopConversion);
            document.getElementById('download-all-btn').addEventListener('click', downloadAllFiles);

            function startConversion() {
                const formData = new FormData();

                Array.from(fileInput.files).forEach(file => {
                    if (file.name.endsWith('.ipynb')) {
                        formData.append('files', file);
                    }
                });

                showLogs('开始上传文件...');

                fetch('/convert', {
                    method: 'POST',
                    body: formData
                })
                    .then(response => response.json())
                    .then(data => {
                        if (data.task_id) {
                            currentTaskId = data.task_id;
                            taskIdDisplay.textContent = `任务ID：${currentTaskId}`;
                            taskInfo.classList.remove('hidden');

                            // 更新界面状态
                            convertBtn.disabled = true;
                            convertBtn.classList.add('hidden');
                            stopBtn.classList.remove('hidden');
                            progressSection.classList.remove('hidden');
                            uploadSection.classList.add('opacity-50');
                            dropArea.classList.add('pointer-events-none');

                            // 开始检查任务状态
                            startStatusCheck();
                        } else if (data.error) {
                            showLogs(`错误: ${data.error}`);
                        }
                    })
                    .catch(error => {
                        showLogs(`上传失败: ${error.message}`);
                    });
            }

            function stopConversion() {
                if (currentTaskId) {
                    fetch(`/delete_task/${currentTaskId}`)
                        .then(response => response.json())
                        .then(() => {
                            stopStatusCheck();
                            resetUI();
                            showLogs('转换任务已取消');
                        });
                }
            }

            function startStatusCheck() {
                // 清除现有的间隔检查
                if (statusCheckInterval) {
                    clearInterval(statusCheckInterval);
                }

                // 立即检查一次
                checkStatus();

                // 设置定期检查
                statusCheckInterval = setInterval(checkStatus, 1000);
            }

            function stopStatusCheck() {
                if (statusCheckInterval) {
                    clearInterval(statusCheckInterval);
                    statusCheckInterval = null;
                }
            }

            function checkStatus() {
                if (!currentTaskId) return;

                fetch(`/status/${currentTaskId}`)
                    .then(response => response.json())
                    .then(data => {
                        // 更新进度
                        progressBar.style.width = `${data.progress}%`;
                        progressText.textContent = `${data.progress}%`;
                        statusText.textContent = getStatusText(data.status);

                        // 更新日志
                        updateLogs(data.logs);

                        // 更新结果
                        if (data.results) {
                            updateResults(data.results);

                            // 检查是否有成功的转换结果，如果有则显示批量下载按钮
                            const hasSuccessResults = Object.values(data.results).some(result => result.status === 'success');
                            if (hasSuccessResults && data.status === 'completed') {
                                document.getElementById('download-all-btn').classList.remove('hidden');
                            } else {
                                document.getElementById('download-all-btn').classList.add('hidden');
                            }
                        }

                        // 检查是否完成
                        if (data.status === 'completed' || data.status === 'error' || data.status === 'cancelled') {
                            stopStatusCheck();
                            stopBtn.classList.add('hidden');
                            convertBtn.textContent = '重置';
                            convertBtn.classList.remove('hidden');
                            convertBtn.disabled = false;
                        }
                    })
                    .catch(error => {
                        console.error('检查状态失败:', error);
                    });
            }

            function getStatusText(status) {
                const statusMap = {
                    'pending': '等待中...',
                    'running': '转换中...',
                    'completed': '转换完成',
                    'error': '发生错误',
                    'cancelled': '已取消'
                };
                return statusMap[status] || status;
            }

            function updateLogs(logs) {
                if (!logs || logs.length === 0) return;

                logsContainer.innerHTML = '';
                logs.forEach(log => {
                    const logElement = document.createElement('p');
                    logElement.textContent = log;

                    // 设置日志颜色
                    if (log.includes('✓')) {
                        logElement.classList.add('text-secondary');
                    } else if (log.includes('✗')) {
                        logElement.classList.add('text-danger');
                    } else if (log.includes('开始转换')) {
                        logElement.classList.add('text-primary');
                    }

                    logsContainer.appendChild(logElement);
                });

                // 滚动到底部
                logsContainer.scrollTop = logsContainer.scrollHeight;
            }

            function showLogs(message) {
                const logElement = document.createElement('p');
                logElement.textContent = message;
                logsContainer.appendChild(logElement);
                logsContainer.scrollTop = logsContainer.scrollHeight;
            }

            function updateResults(results) {
                resultsList.innerHTML = '';
                resultsSection.classList.remove('hidden');

                Object.entries(results).forEach(([filePath, result]) => {
                    const fileName = filePath.split('/').pop().replace('.ipynb', '');
                    const mdFileName = fileName + '.md';

                    const resultItem = document.createElement('div');
                    resultItem.classList.add('p-3', 'rounded-lg', 'border', 'flex', 'justify-between', 'items-center');

                    let statusClass = '';
                    let statusIcon = '';
                    let statusText = '';

                    switch (result.status) {
                        case 'success':
                            statusClass = 'bg-green-50 border-green-200';
                            statusIcon = '<i class="fa fa-check-circle text-secondary"></i>';
                            statusText = '转换成功';
                            break;
                        case 'failed':
                            statusClass = 'bg-red-50 border-red-200';
                            statusIcon = '<i class="fa fa-times-circle text-danger"></i>';
                            statusText = '转换失败';
                            break;
                        case 'error':
                            statusClass = 'bg-orange-50 border-orange-200';
                            statusIcon = '<i class="fa fa-exclamation-circle text-warning"></i>';
                            statusText = '处理错误';
                            break;
                        case 'timeout':
                            statusClass = 'bg-yellow-50 border-yellow-200';
                            statusIcon = '<i class="fa fa-clock-o text-warning"></i>';
                            statusText = '转换超时';
                            break;
                    }

                    resultItem.classList.add(...statusClass.split(' '));

                    let downloadButton = '';
                    if (result.status === 'success' && currentTaskId) {
                        downloadButton = `<a href="/download/${currentTaskId}/${mdFileName}" class="bg-primary hover:bg-primary/90 text-white py-1 px-3 rounded text-sm transition-all-300 flex items-center">
                            <i class="fa fa-download mr-1"></i>下载
                        </a>`;
                    }

                    resultItem.innerHTML = `
                        <div class="flex items-center">
                            ${statusIcon}
                            <div class="ml-2">
                                <div class="font-medium">${fileName}</div>
                                <div class="text-xs text-gray-600">${statusText}</div>
                            </div>
                        </div>
                        ${downloadButton}
                    `;

                    resultsList.appendChild(resultItem);
                });
            }

            clearLogsBtn.addEventListener('click', () => {
                logsContainer.innerHTML = '<p class="text-gray-500 italic">等待转换开始...</p>';
            });

            function resetUI() {
                progressBar.style.width = '0%';
                progressText.textContent = '0%';
                statusText.textContent = '准备就绪';
                currentTaskId = null;
                taskInfo.classList.add('hidden');
                resultsSection.classList.add('hidden');
                progressSection.classList.add('hidden');
                uploadSection.classList.remove('opacity-50');
                dropArea.classList.remove('pointer-events-none');
                stopBtn.classList.add('hidden');
                document.getElementById('download-all-btn').classList.add('hidden');
                convertBtn.textContent = '开始转换';
                convertBtn.classList.remove('hidden');
                convertBtn.disabled = fileInput.files.length === 0;
            }

            function resetApplication() {
                // 如果有当前任务，删除任务并清理文件
                if (currentTaskId) {
                    fetch(`/delete_task/${currentTaskId}`)
                        .then(response => response.json())
                        .then(() => {
                            // 重置UI
                            fileInput.value = '';
                            updateFileList();
                            resetUI();
                            showLogs('应用已重置');
                        })
                        .catch(error => {
                            console.error('重置失败:', error);
                            // 即使API调用失败，也重置UI
                            fileInput.value = '';
                            updateFileList();
                            resetUI();
                            showLogs('应用UI已重置');
                        });
                } else {
                    // 没有任务时直接重置
                    fileInput.value = '';
                    updateFileList();
                    resetUI();
                    showLogs('应用已重置');
                }
            }

            function downloadAllFiles() {
                if (currentTaskId) {
                    fetch(`/download_all/${currentTaskId}`)
                        .then(response => {
                            if (response.ok) {
                                return response.blob();
                            } else {
                                throw new Error('批量下载失败');
                            }
                        })
                        .then(blob => {
                            // 创建下载链接
                            const url = window.URL.createObjectURL(blob);
                            const a = document.createElement('a');
                            a.href = url;
                            a.download = `converted_files_${new Date().toISOString().slice(0, 10)}.zip`;
                            document.body.appendChild(a);
                            a.click();

                            // 清理
                            setTimeout(() => {
                                document.body.removeChild(a);
                                window.URL.revokeObjectURL(url);
                            }, 0);

                            showLogs('批量下载已开始');
                        })
                        .catch(error => {
                            showLogs(`批量下载失败: ${error.message}`);
                        });
                }
            }
        });
    </script>
</body>

</html>